/* *******************************************************************************
 *  OPENING.HH
 * *******************************************************************************/

/* *
 * Copyright (C) 2005 Atul S. Vasu
 *
 * This program is free software; you cn redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 * */

/* *
 * Contact Details:
 *
 * mail
 *  Atul S. Vasu, Flat No. 3, Govt Quarters, Kowdiar,
 *  Thiruvananthapuram, Kerala, India. 695003.
 * email
 *        - atulsvasu@gmail.com
 *        - atulsv@cse.iitm.ernet.in (till early 2007).
 * */

struct book_tree {
  struct node {
    node* child, * sibling;
    move m;
    int score;
    node():child(0),sibling(0),m(OUT,OUT),score(0) {}
    ~node() { delete child; delete sibling; }
  private:
    node(const node&);
    bool operator = (const node&);
  } * Root;

  const char* file_name;
  bool initialized;

  book_tree(const char* fname):Root(0), file_name(fname), initialized(false) {
  }

  void init() {
    if (initialized) {
      return;
    }
    std::ifstream fin(file_name);
    Root = new node;
    create(&Root,fin,false);
    fin.close();
    initialized = true;
  }


  ~book_tree(){ delete Root; }

  void create(node** t, std::istream& is,bool side) {
    while(true) {
      char a1,a2,a3,a4;
      if(!(is.get(a1))) { delete *t; *t=0; return; }
      if(a1=='}') { delete *t; *t=0; return; }
      is.get(a2);
      is.get(a3);
      is.get(a4);

      move m((a1-'a')+(a2-'1')*n, (a3-'a')+(a4-'1')*n);
      char ch;

      is.get(ch);
      if(ch=='=') {
	is.get(ch);
	switch(ch) {
	case 'n': if(side) m.promote=BKNIGHT; else m.promote=WKNIGHT; break;
	case 'b': if(side) m.promote=BBISHOP; else m.promote=WBISHOP; break;
	case 'r': if(side) m.promote=BROOK; else m.promote=WROOK; break;
	case 'q': if(side) m.promote=BQUEEN; else m.promote=WQUEEN; break;
	default: m.promote=EMPTY; break;
	}
	is.get(ch);
      }
      // ch=='[' assert.
      (*t)->m = m;
      is>>(*t)->score;
      is>>ch;
      // ch==']' assert

      while(is.get(ch))	if(ch=='{')  break;
      if(ch=='{') {
	(*t)->child = new node;
	create(&((*t)->child),is,!side);
	(*t)->sibling = new node;
	t=&((*t)->sibling);
      }
    }
  }
  bool query(move& best) {
    init();
    node *Nd = Root;

    for(move_list::iterator it=En.ML.begin();it!=En.ML.end();++it){
      move m=*it;
      while(Nd) {
	if(Nd->m==m) break;
	Nd=Nd->sibling;
      }
      if(Nd)
	Nd=Nd->child;
      else
	return false;
    }
    if(Nd) {
      bool accept=false;	
      if(ran_move) {
	node *Top=Nd;
	int tot_score=0;
	while(Nd) {
	  if(Nd->score>0) {	
		  tot_score+=Nd->score;
	  }
	  Nd=Nd->sibling;
	}
	int rand_seed=static_cast<int>((std::rand()/(RAND_MAX+1.0))*tot_score);
	
	tot_score=0; best=Top->m; Nd=Top;
	while(Nd) {
	  if(Nd->score>0) {	
		  tot_score+=Nd->score;
		  if(tot_score>=rand_seed) {
		    best=Nd->m;
		    accept=true;
		    break;
		  }
	  }
	  Nd=Nd->sibling;
	}
      } else {
	int max_score=-MAX;
	for(;Nd;Nd=Nd->sibling) {
          if (debug) {
            mout <<" For Move: " << Nd->m << " score = " << Nd->score << std::endl;
          }
	  if(Nd->score>max_score) {
	    max_score=Nd->score;
	    best=Nd->m;
	    accept=true;
	  }
        }
      }
      return true;
    }else
      return false;
  }
 private:
  book_tree(const book_tree&);
  book_tree operator = (const book_tree&);
} BT2("open.book");

/// MACHINE-LEARNED
bool refer_opening(move& m) {
  return BT2.query(m);
}
